﻿using System.Diagnostics;
using DimensionsHelper.LanguageService.Syntax;

namespace DimensionsHelper.LanguageService.Symbols;

/// <summary>
///     模块符号
/// </summary>
public sealed class ModuleSymbol : AbstractTypeSymbol
{
    private readonly List<ModuleSignature> _signatures;

    internal ModuleSymbol(ModuleSignature signature, ModuleSymbol? containingModule = null)
        : base(SymbolKinds.Module, TypeKinds.Module)
    {
        _signatures = [signature];
        ContainingModule = containingModule;
        LocationMap.AddLocation(signature.NameIdentifier.GetLocation());
    }


    public override string Name => Declaration.Name;


    public override bool IsModule => true;

    /// <summary>
    ///     获取第一个声明节点
    /// </summary>
    public override ModuleSignature Declaration => _signatures[0];


    public override ModuleSymbol? ContainingModule { get; }


    public override ModuleSymbol? ContainingSymbol => ContainingModule;


    /// <summary>
    ///     获取指定名称的类型成员符号
    /// </summary>
    /// <param name="name">成员名</param>
    public override ITypeSymbol? LookupNamedMember(string name)
    {
        return NamedMembersCount == 0
            ? null
            : NamedMembers.LookupDeclaredSymbol(name) as ITypeSymbol;
    }


    /// <summary>
    ///     使用全限定名查找成员符号，如果第一个符号
    /// </summary>
    /// <param name="qualified">全限定名列表，名称顺序很重要</param>
    public ISymbol? LookupNamedMember(string[] qualified)
    {
        ISymbol? result = null;

        // 如果只有一个限定名，只在当前的成员符号中查找。
        if (qualified.Length == 1)
        {
            return base.LookupNamedMember(qualified[0]);
        }

        for (int i = 0; i < qualified.Length; i++)
        {
            string name = qualified[i];

            // 如果第一个名称是当前符号，跳过
            if (i == 0 && name.Equals(Name, StringComparison.OrdinalIgnoreCase))
            {
                continue;
            }

            switch (result)
            {
                case null:
                {
                    result = LookupNamedMember(name);
                    break;
                }

                case { Kind: SymbolKinds.Module }:
                {
                    result = ((ModuleSymbol)result).LookupNamedMember(name);
                    break;
                }

                case { Kind: SymbolKinds.NamedType }:
                {
                    result = ((NamedTypeSymbol)result).LookupNamedMember(name);
                    break;
                }

                default:
                    return null;
            }

            if (result == null)
            {
                return null;
            }
        }

        return result;
    }


    public override bool Redeclare(ISymbol symbol)
    {
        Debug.Assert(symbol is ModuleSymbol);

        ModuleSymbol moduleSymbol = (ModuleSymbol)symbol;
        foreach (ISymbol member in moduleSymbol.GetMembers())
        {
            TryAddMember((ITypeSymbol)member);
        }

        LocationMap.AddLocations(moduleSymbol.LocationMap.GetLocations());
        _signatures.AddRange(moduleSymbol._signatures);
        return true;
    }
}